home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / mg2a_src.zip / MATCH.C < prev    next >
C/C++ Source or Header  |  1988-08-23  |  5KB  |  190 lines

  1. /*
  2.  * Name:    MicroEMACS
  3.  *        Limited parenthesis matching routines
  4.  *
  5.  * The hacks in this file implement automatic matching
  6.  * of (), [], {}, and other characters.     It would be
  7.  * better to have a full-blown syntax table, but there's
  8.  * enough overhead in the editor as it is.
  9.  *
  10.  * Since I often edit Scribe code, I've made it possible to
  11.  * blink arbitrary characters -- just bind delimiter characters
  12.  * to "blink-matching-paren-hack"
  13.  */
  14. #include    "def.h"
  15. #include    "key.h"
  16.  
  17. static int    balance();
  18. static VOID    displaymatch();
  19.  
  20. /* Balance table. When balance() encounters a character
  21.  * that is to be matched, it first searches this table
  22.  * for a balancing left-side character.     If the character
  23.  * is not in the table, the character is balanced by itself.
  24.  * This is to allow delimiters in Scribe documents to be matched.
  25.  */
  26.  
  27. static struct balance {
  28.     char left, right;
  29. } bal[] = {
  30.     { '(', ')' },
  31.     { '[', ']' },
  32.     { '{', '}' },
  33.     { '<', '>' },
  34.     { '\0','\0'}
  35. };
  36.  
  37. /*
  38.  * Self-insert character, then show matching character,
  39.  * if any.  Bound to "blink-matching-paren-command".
  40.  */
  41.  
  42. showmatch(f, n)
  43. {
  44.     register int  i, s;
  45.  
  46.     if (f & FFRAND) return FALSE;
  47.     for (i = 0; i < n; i++) {
  48.         if ((s = selfinsert(FFRAND, 1)) != TRUE)
  49.             return s;
  50.         if (balance() != TRUE) /* unbalanced -- warn user */
  51.             ttbeep();
  52.     }
  53.     return TRUE;
  54. }
  55.  
  56. /*
  57.  * Search for and display a matching character.
  58.  *
  59.  * This routine does the real work of searching backward
  60.  * for a balancing character.  If such a balancing character
  61.  * is found, it uses displaymatch() to display the match.
  62.  */
  63.  
  64. static balance()
  65. {
  66.     register LINE    *clp;
  67.     register int    cbo;
  68.     int    c;
  69.     int    i;
  70.     int    rbal, lbal;
  71.     int    depth;
  72.  
  73.     rbal = key.k_chars[key.k_count-1];
  74.  
  75.     /* See if there is a matching character -- default to the same */
  76.  
  77.     lbal = rbal;
  78.     for (i = 0; bal[i].right != '\0'; i++)
  79.         if (bal[i].right == rbal) {
  80.             lbal = bal[i].left;
  81.             break;
  82.         }
  83.  
  84.     /* Move behind the inserted character.    We are always guaranteed    */
  85.     /* that there is at least one character on the line, since one was  */
  86.     /* just self-inserted by blinkparen.                    */
  87.  
  88.     clp = curwp->w_dotp;
  89.     cbo = curwp->w_doto - 1;
  90.  
  91.     depth = 0;            /* init nesting depth        */
  92.  
  93.     for (;;) {
  94.         if (cbo == 0) {            /* beginning of line    */
  95.             clp = lback(clp);
  96.             if (clp == curbp->b_linep)
  97.                 return (FALSE);
  98.             cbo = llength(clp)+1;
  99.         }
  100.         if (--cbo == llength(clp))    /* end of line        */
  101.             c = '\n';
  102.         else
  103.             c = lgetc(clp,cbo);    /* somewhere in middle    */
  104.  
  105.         /* Check for a matching character.  If still in a nested */
  106.         /* level, pop out of it and continue search.  This check */
  107.         /* is done before the nesting check so single-character     */
  108.         /* matches will work too.                 */
  109.         if (c == lbal) {
  110.             if (depth == 0) {
  111.                 displaymatch(clp,cbo);
  112.                 return (TRUE);
  113.             }
  114.             else
  115.                 depth--;
  116.         }
  117.         /* Check for another level of nesting.    */
  118.         if (c == rbal)
  119.             depth++;
  120.     }
  121.     /*NOTREACHED*/
  122. }
  123.  
  124.  
  125. /*
  126.  * Display matching character.
  127.  * Matching characters that are not in the current window
  128.  * are displayed in the echo line. If in the current
  129.  * window, move dot to the matching character,
  130.  * sit there a while, then move back.
  131.  */
  132.  
  133. static VOID displaymatch(clp, cbo)
  134. register LINE *clp;
  135. register int  cbo;
  136. {
  137.     register LINE    *tlp;
  138.     register int    tbo;
  139.     register int    cp;
  140.     register int    bufo;
  141.     register int    c;
  142.     int        inwindow;
  143.     char        buf[NLINE];
  144.  
  145.     /* Figure out if matching char is in current window by    */
  146.     /* searching from the top of the window to dot.        */
  147.  
  148.     inwindow = FALSE;
  149.     for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
  150.         if (tlp == clp)
  151.             inwindow = TRUE;
  152.  
  153.     if (inwindow == TRUE) {
  154.         tlp = curwp->w_dotp;    /* save current position */
  155.         tbo = curwp->w_doto;
  156.  
  157.         curwp->w_dotp  = clp;    /* move to new position */
  158.         curwp->w_doto  = cbo;
  159.         curwp->w_flag |= WFMOVE;
  160.  
  161.         update();        /* show match */
  162.         sleep(1);        /* wait a bit */
  163.  
  164.         curwp->w_dotp    = tlp;    /* return to old position */
  165.         curwp->w_doto    = tbo;
  166.         curwp->w_flag  |= WFMOVE;
  167.         update();
  168.     }
  169.     else {    /* match not in this window so display line in echo area */
  170.         bufo = 0;
  171.         for (cp = 0; cp < llength(clp); cp++) { /* expand tabs    */
  172.             c = lgetc(clp,cp);
  173.             if (c != '\t'
  174. #ifdef    NOTAB
  175.                 || (curbp->b_flag & BFNOTAB)
  176. #endif
  177.                 ) if(ISCTRL(c)) {
  178.                     buf[bufo++] = '^';
  179.                     buf[bufo++] = CCHR(c);
  180.                 } else buf[bufo++] = c;
  181.             else
  182.                 do {
  183.                     buf[bufo++] = ' ';
  184.                 } while (bufo & 7);
  185.         }
  186.         buf[bufo++] = '\0';
  187.         ewprintf("Matches %s",buf);
  188.     }
  189. }
  190.